//***************************************************************************//
//*
//* 内容摘要：Vander解码处理
//*	
//* 当前版本：V1.0		
//* 作    者：zhfayuan
//* 完成日期：2016-8-21
//**************************************************************************//
#ifndef CSDVAND_DEC_H
#define CSDVAND_DEC_H


#include "SDVandermonde.h"

typedef enum 
{
    VANDERMONDEDEC_OK =  0, 
    VANDERMONDEDEC_ERR = 3000,                  
    VANDERMONDEDEC_NOT_INITED,
    VANDERMONDEDEC_ID_INVALID,                 
    VANDERMONDEDEC_IS_IDLE,                      
    VANDERMONDEDEC_ID_ISFULL,                  
    VANDERMONDEDEC_INVALID_POINTOR,      
    VANDERMONDEDEC_MALLOC_FAILED,           
    VANDERMONDEDEC_BUFFER_NOT_ENOUGH, 
    VANDERMONDEDEC_REDUNT_IS_ZERO,         
    VANDERMONDEDEC_NOT_START_DEC,          
    VANDERMONDEDEC_SET_PARAM_FAILED
}E_VANDERMONDE_DEC_ERROR_CODE;


typedef enum 
{
    VANDERMONDE_DEC_IDLE,
    VANDERMONDE_DEC_IN_USED
}E_VANDERMONDE_DEC_STATUS;
    

typedef struct _t_vandermonde_dec
{
    UINT32 uStatus; 
    UINT32 uiPacketMaxLen;
    T_VANDER_MONDE *pDecHdl;

    T_FEC_DATA tData[MAX_GROUP_SIZE];


    UINT32 uiDecTimes;
    UINT32 uiDecErr;
    UINT32 uiDecBufferNotEnough;
}T_VANDERMONDE_DEC;


#define GF_BITS  8  /* code over GF(2**GF_BITS)*/
#define GF_SIZE ((1 << GF_BITS) - 1)    /* powers of \alpha */

#define FEC_2K_SIZE                	1024*2
#define PRE_ALLOC_SIZE 			   	1

/*
 * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
 * faster to use a multiplication table.
 *
 * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
 * many numbers by the same constant. In this case the first
 * call sets the constant, and others perform the multiplications.
 * A value related to the multiplication is held in a local variable
 * declared with USE_GF_MULC . See usage in addmul1().
 */

#define gf_mul(x,y) gf_mul_table[x][y]

#define USE_GF_MULC register gf * __gf_mulc_
#define GF_MULC0(c) (__gf_mulc_ = gf_mul_table[(c)])
#define GF_ADDMULC(dst, x) ((dst) ^= __gf_mulc_[(x)])

class CSDVanderDec
{
public:
	CSDVanderDec()
	{
		m_pDecIndex = (INT32*)malloc(sizeof(UINT32)*MAX_GROUP_SIZE);
		m_pDecVanderMonde = (gf*)malloc( sizeof(gf) * (MAX_GROUP_SIZE*(MAX_GROUP_SIZE+MAX_GROUP_SIZE)) );
		memset(m_pDecIndex, 0, sizeof(UINT32)*MAX_GROUP_SIZE);
		memset(m_pDecVanderMonde, 0, sizeof(gf) * (MAX_GROUP_SIZE*(MAX_GROUP_SIZE+MAX_GROUP_SIZE)));
		VanderDec_CreateNew();
	}
	~CSDVanderDec()
	{
		VanderDec_Destroy();
		if (m_pDecIndex != NULL)
		{
			free(m_pDecIndex);
			m_pDecIndex = NULL;
		}
		if (m_pDecVanderMonde != NULL)
		{
			free(m_pDecVanderMonde);
			m_pDecVanderMonde = NULL;
		}	
	}
	
	INT32 vandermondedec_setparam(UINT32 eFecParamType, void *value);
	INT32 vandermondedec_getparam(UINT32 eFecParamType, VOID *value);
	INT32 vandermonde_decode(T_FEC_DATA *ptMediaData, T_FEC_DATA *ptParityData, VOID *pDecParam);	

private:

	T_VANDERMONDE_DEC *pVanderDec;

	INT32*     m_pDecIndex;
	gf*        m_pDecVanderMonde; 
	
	gf  gf_exp[2*GF_SIZE];   /* index->poly form conversion table    */
	int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table    */
	gf  inverse[GF_SIZE+1];  /* inverse of field elem.               */
                             /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */	
	const char *allPp[17];
	gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];	
	//add for preprocess
	unsigned char *g_encmatrix;
	//end
	unsigned char g_auGroupSize[11];
	unsigned char g_uSupportGroupSizeNum;	
	
	void init_static_var(void);
	void VanderDec_CreateNew(void);
	void VanderDec_Destroy(void);
	T_VANDER_MONDE * vander_monde_new(void);
	void vander_monde_free(T_VANDER_MONDE *p);
	bool init_vandermonde(void);
	void uninit_vandermonde(void);
	void generate_gf(void);
	void init_mul_table(void);
	gf modnn(int x);
	bool initEncMatrix(void);
	int invert_vdm(gf *src, int k);
	void addmul(gf *dst1, gf *src1, gf c, int sz);
	void matmul(gf *a, gf *b, gf *c, int n, int k, int m);
	int vander_monde_decode(T_VANDER_MONDE *code, 
	                                T_FEC_DATA *recvpkt, 
	                                T_FEC_DATA *outpkt, 
	                                int index[], 
	                                int k, 
	                                int n,
	                                int sz);
	int vander_monde_set_param(T_VANDER_MONDE *code, int k, int n);
	gf* build_decode_matrix(T_VANDER_MONDE *code, int index[], gf *matrix);	
	int invert_mat(gf *src, int k);
		
};
#endif
